<!--
 * 搜索来源卡片组件
 * 功能：显示单个搜索来源的信息，包括标题、描述、URL等
 * 作者：MetasoCreator Team
 * 创建时间：2025-01-19
 * 修改时间：2025-01-19
-->

<template>
  <div class="source-card" @click="handleClick">
    <div class="card-header">
      <div class="source-favicon">
        <img
          v-if="faviconUrl"
          :src="faviconUrl"
          :alt="source.title"
          @error="handleFaviconError"
          class="favicon-img"
        />
        <el-icon v-else class="default-icon">
          <Document />
        </el-icon>
      </div>
      <div class="source-info">
        <div class="source-title" :title="source.title">
          {{ source.title || '未知标题' }}
        </div>
        <div class="source-domain" :title="sourceDomain">
          {{ sourceDomain }}
        </div>
      </div>
      <div class="card-actions">
        <el-dropdown trigger="click" @command="handleAction">
          <el-button size="small" text circle>
            <el-icon><MoreFilled /></el-icon>
          </el-button>
          <template #dropdown>
            <el-dropdown-menu>
              <el-dropdown-item command="open">
                <el-icon><Link /></el-icon>
                <span>打开链接</span>
              </el-dropdown-item>
              <el-dropdown-item command="read">
                <el-icon><View /></el-icon>
                <span>阅读内容</span>
              </el-dropdown-item>
              <el-dropdown-item command="copy">
                <el-icon><DocumentCopy /></el-icon>
                <span>复制链接</span>
              </el-dropdown-item>
              <el-dropdown-item command="share" divided>
                <el-icon><Share /></el-icon>
                <span>分享</span>
              </el-dropdown-item>
            </el-dropdown-menu>
          </template>
        </el-dropdown>
      </div>
    </div>

    <div v-if="source.description" class="card-content">
      <p class="source-description" :title="source.description">
        {{ truncatedDescription }}
      </p>
    </div>

    <div class="card-footer">
      <div class="source-meta">
        <el-tag
          v-if="source.type"
          size="small"
          :type="getTypeTagType(source.type)"
          class="source-type"
        >
          {{ getTypeLabel(source.type) }}
        </el-tag>
        <span v-if="source.publishTime" class="publish-time">
          {{ formatTime(source.publishTime) }}
        </span>
      </div>
      <div class="card-buttons">
        <el-button
          size="small"
          type="primary"
          text
          @click.stop="handleRead"
          title="阅读内容"
        >
          <el-icon><View /></el-icon>
        </el-button>
        <el-button
          size="small"
          text
          @click.stop="handleOpen"
          title="打开链接"
        >
          <el-icon><Link /></el-icon>
        </el-button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed } from 'vue'
import { ElMessage } from 'element-plus'
import {
  Document,
  MoreFilled,
  Link,
  View,
  DocumentCopy,
  Share
} from '@element-plus/icons-vue'

// Props
const props = defineProps({
  source: {
    type: Object,
    required: true,
    validator: (source) => {
      return source && typeof source === 'object' && source.url
    }
  }
})

// Emits
const emit = defineEmits(['click', 'read'])

// 响应式数据
const faviconError = ref(false)

// 计算属性
const sourceDomain = computed(() => {
  try {
    const url = new URL(props.source.url)
    return url.hostname.replace('www.', '')
  } catch {
    return '未知来源'
  }
})

const faviconUrl = computed(() => {
  if (faviconError.value) return null
  try {
    const url = new URL(props.source.url)
    return `https://www.google.com/s2/favicons?domain=${url.hostname}&sz=16`
  } catch {
    return null
  }
})

const truncatedDescription = computed(() => {
  const description = props.source.description || ''
  const maxLength = 120
  if (description.length <= maxLength) {
    return description
  }
  return description.substring(0, maxLength) + '...'
})

// 方法
const handleClick = () => {
  emit('click', props.source)
}

const handleRead = () => {
  emit('read', props.source)
}

const handleOpen = () => {
  if (props.source.url) {
    window.open(props.source.url, '_blank', 'noopener,noreferrer')
  }
}

const handleFaviconError = () => {
  faviconError.value = true
}

const handleAction = (command) => {
  switch (command) {
    case 'open':
      handleOpen()
      break
    case 'read':
      handleRead()
      break
    case 'copy':
      copyToClipboard(props.source.url)
      break
    case 'share':
      shareSource()
      break
  }
}

const copyToClipboard = async (text) => {
  try {
    await navigator.clipboard.writeText(text)
    ElMessage.success('链接已复制到剪贴板')
  } catch {
    // 降级方案
    const textArea = document.createElement('textarea')
    textArea.value = text
    document.body.appendChild(textArea)
    textArea.select()
    try {
      document.execCommand('copy')
      ElMessage.success('链接已复制到剪贴板')
    } catch {
      ElMessage.error('复制失败')
    }
    document.body.removeChild(textArea)
  }
}

const shareSource = async () => {
  const shareData = {
    title: props.source.title || '分享链接',
    text: props.source.description || '',
    url: props.source.url
  }

  if (navigator.share) {
    try {
      await navigator.share(shareData)
    } catch (error) {
      if (error.name !== 'AbortError') {
        copyToClipboard(props.source.url)
      }
    }
  } else {
    copyToClipboard(props.source.url)
  }
}

const getTypeLabel = (type) => {
  const labels = {
    web: '网页',
    academic: '学术',
    news: '新闻',
    blog: '博客',
    forum: '论坛',
    video: '视频',
    image: '图片',
    document: '文档'
  }
  return labels[type] || type
}

const getTypeTagType = (type) => {
  const types = {
    web: 'primary',
    academic: 'success',
    news: 'warning',
    blog: 'info',
    forum: 'danger',
    video: 'warning',
    image: 'success',
    document: 'info'
  }
  return types[type] || 'info'
}

const formatTime = (timestamp) => {
  if (!timestamp) return ''
  
  const date = new Date(timestamp)
  const now = new Date()
  const diff = now - date
  
  if (diff < 60000) { // 1分钟内
    return '刚刚'
  } else if (diff < 3600000) { // 1小时内
    return `${Math.floor(diff / 60000)}分钟前`
  } else if (diff < 86400000) { // 24小时内
    return `${Math.floor(diff / 3600000)}小时前`
  } else if (diff < 604800000) { // 7天内
    return `${Math.floor(diff / 86400000)}天前`
  } else {
    return date.toLocaleDateString()
  }
}
</script>

<style scoped>
.source-card {
  background: var(--bg-primary);
  border: 1px solid var(--border-color-light);
  border-radius: 8px;
  padding: 12px;
  margin-bottom: 8px;
  cursor: pointer;
  transition: all 0.3s ease;
  position: relative;
  overflow: hidden;
}

.source-card:hover {
  border-color: var(--color-primary);
  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.15);
  transform: translateY(-2px);
}

.source-card:active {
  transform: translateY(0);
}

.card-header {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin-bottom: 8px;
}

.source-favicon {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.favicon-img {
  width: 16px;
  height: 16px;
  border-radius: 2px;
}

.default-icon {
  font-size: 16px;
  color: var(--text-secondary);
}

.source-info {
  flex: 1;
  min-width: 0;
}

.source-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.4;
  margin-bottom: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.source-domain {
  font-size: 12px;
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.card-actions {
  flex-shrink: 0;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.source-card:hover .card-actions {
  opacity: 1;
}

.card-content {
  margin-bottom: 8px;
}

.source-description {
  font-size: 13px;
  color: var(--text-secondary);
  line-height: 1.5;
  margin: 0;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
}

.card-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.source-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 0;
}

.source-type {
  flex-shrink: 0;
}

.publish-time {
  font-size: 11px;
  color: var(--text-placeholder);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.card-buttons {
  display: flex;
  gap: 4px;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.source-card:hover .card-buttons {
  opacity: 1;
}

/* 加载状态 */
.source-card.loading {
  pointer-events: none;
  opacity: 0.6;
}

.source-card.loading::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(
    90deg,
    transparent,
    rgba(255, 255, 255, 0.4),
    transparent
  );
  animation: shimmer 1.5s infinite;
}

@keyframes shimmer {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(100%);
  }
}

/* 响应式设计 */
@media (max-width: 768px) {
  .source-card {
    padding: 10px;
  }
  
  .source-title {
    font-size: 13px;
  }
  
  .source-description {
    font-size: 12px;
    -webkit-line-clamp: 2;
  }
  
  .card-actions,
  .card-buttons {
    opacity: 1; /* 移动端始终显示 */
  }
}

/* 暗色主题适配 */
:root[data-theme="dark"] .source-card {
  background: var(--bg-primary);
  border-color: var(--border-color-light);
}

:root[data-theme="dark"] .source-card:hover {
  border-color: var(--color-primary);
  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.25);
}

:root[data-theme="dark"] .source-card.loading::after {
  background: linear-gradient(
    90deg,
    transparent,
    rgba(255, 255, 255, 0.1),
    transparent
  );
}

/* 焦点状态 */
.source-card:focus {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* 选中状态 */
.source-card.selected {
  border-color: var(--color-primary);
  background: var(--color-primary-light);
}

/* 错误状态 */
.source-card.error {
  border-color: var(--color-danger);
  background: var(--color-danger-light);
}

.source-card.error .source-title {
  color: var(--color-danger);
}
</style>